#include "PatchTree.h"

PatchTree::PatchTree(){
}

void PatchTree::generateTree(vector<Point3> rootCoords, int _numDivisions, MyColor initialEnergy){
	numDivisions = _numDivisions;
	root.patchInfo.setPoints(rootCoords.at(0), rootCoords.at(1), rootCoords.at(2), rootCoords.at(3));
	root.patchInfo.radiantEnergy = initialEnergy;
	root.patchInfo.illuminance = initialEnergy;

	PatchTreeNode* patchA = new PatchTreeNode();
	PatchTreeNode* patchB = new PatchTreeNode();

	double midAx = root.patchInfo.topLeft.x + ((root.patchInfo.topRight.x - root.patchInfo.topLeft.x) / 2.0);
	double midAy = root.patchInfo.topLeft.y + ((root.patchInfo.topRight.y - root.patchInfo.topLeft.y) / 2.0);
	double midAz = root.patchInfo.topLeft.z + ((root.patchInfo.topRight.z - root.patchInfo.topLeft.z) / 2.0);
	double midBx = root.patchInfo.bottomLeft.x + ((root.patchInfo.bottomRight.x - root.patchInfo.bottomLeft.x) / 2.0);
	double midBy = root.patchInfo.bottomLeft.y + ((root.patchInfo.bottomRight.y - root.patchInfo.bottomLeft.y) / 2.0);
	double midBz = root.patchInfo.bottomLeft.z + ((root.patchInfo.bottomRight.z - root.patchInfo.bottomLeft.z) / 2.0);
	Point3 midpointTop(midAx, midAy, midAz);
	Point3 midpointBottom(midBx, midBy, midBz);

	patchA->patchInfo.setPoints(root.patchInfo.topLeft, root.patchInfo.bottomLeft, midpointBottom, midpointTop);
	patchB->patchInfo.setPoints(midpointTop, midpointBottom, root.patchInfo.bottomRight, root.patchInfo.topRight);
	patchA->patchInfo.radiantEnergy = root.patchInfo.radiantEnergy/2.0;
	patchB->patchInfo.radiantEnergy = root.patchInfo.radiantEnergy/2.0;
	patchA->patchInfo.illuminance = root.patchInfo.illuminance/2.0;
	patchB->patchInfo.illuminance = root.patchInfo.illuminance/2.0;
	root.childA = patchA;
	root.childB = patchB;

	generateTree(patchA, 1);
	generateTree(patchB, 1);
}

void PatchTree::generateTree(PatchTreeNode* curNode, int depth){
	if(depth < numDivisions*2){
		PatchTreeNode* patchA = new PatchTreeNode();
		PatchTreeNode* patchB = new PatchTreeNode();

		//Even iterations are vertical cuts
		if(depth%2 == 0){
			double midAx = curNode->patchInfo.topLeft.x + ((curNode->patchInfo.topRight.x - curNode->patchInfo.topLeft.x) / 2.0);
			double midAy = curNode->patchInfo.topLeft.y + ((curNode->patchInfo.topRight.y - curNode->patchInfo.topLeft.y) / 2.0);
			double midAz = curNode->patchInfo.topLeft.z + ((curNode->patchInfo.topRight.z - curNode->patchInfo.topLeft.z) / 2.0);
			double midBx = curNode->patchInfo.bottomLeft.x + ((curNode->patchInfo.bottomRight.x - curNode->patchInfo.bottomLeft.x) / 2.0);
			double midBy = curNode->patchInfo.bottomLeft.y + ((curNode->patchInfo.bottomRight.y - curNode->patchInfo.bottomLeft.y) / 2.0);
			double midBz = curNode->patchInfo.bottomLeft.z + ((curNode->patchInfo.bottomRight.z - curNode->patchInfo.bottomLeft.z) / 2.0);
			Point3 midpointTop(midAx, midAy, midAz);
			Point3 midpointBottom(midBx, midBy, midBz);

			patchA->patchInfo.setPoints(curNode->patchInfo.topLeft, curNode->patchInfo.bottomLeft, midpointBottom, midpointTop);
			patchB->patchInfo.setPoints(midpointTop, midpointBottom, curNode->patchInfo.bottomRight, curNode->patchInfo.topRight);
		}
		//Odd iterations are horizontal cuts
		else{
			double midAx = curNode->patchInfo.bottomLeft.x + ((curNode->patchInfo.topLeft.x - curNode->patchInfo.bottomLeft.x) / 2.0);
			double midAy = curNode->patchInfo.bottomLeft.y + ((curNode->patchInfo.topLeft.y - curNode->patchInfo.bottomLeft.y) / 2.0);
			double midAz = curNode->patchInfo.bottomLeft.z + ((curNode->patchInfo.topLeft.z - curNode->patchInfo.bottomLeft.z) / 2.0);
			double midBx = curNode->patchInfo.bottomRight.x + ((curNode->patchInfo.topRight.x - curNode->patchInfo.bottomRight.x) / 2.0);
			double midBy = curNode->patchInfo.bottomRight.y + ((curNode->patchInfo.topRight.y - curNode->patchInfo.bottomRight.y) / 2.0);
			double midBz = curNode->patchInfo.bottomRight.z + ((curNode->patchInfo.topRight.z - curNode->patchInfo.bottomRight.z) / 2.0);
			Point3 midpointLeft(midAx, midAy, midAz);
			Point3 midpointRight(midBx, midBy, midBz);

			patchA->patchInfo.setPoints(curNode->patchInfo.topLeft, midpointLeft, midpointRight, curNode->patchInfo.topRight);
			patchB->patchInfo.setPoints(midpointLeft, curNode->patchInfo.bottomLeft, curNode->patchInfo.bottomRight, midpointRight);
		}

		patchA->patchInfo.radiantEnergy = curNode->patchInfo.radiantEnergy/2.0;
		patchB->patchInfo.radiantEnergy = curNode->patchInfo.radiantEnergy/2.0;
		patchA->patchInfo.illuminance = curNode->patchInfo.illuminance/2.0;
		patchB->patchInfo.illuminance = curNode->patchInfo.illuminance/2.0;
		curNode->childA = patchA;
		curNode->childB = patchB;
		generateTree(patchA, depth+1);
		generateTree(patchB, depth+1);
	}
	else{
		curNode->childA = curNode->childB = 0;
	}
}

vector<Patch*> PatchTree::getPatchList(){
	if(root.childA != NULL && root.childB != NULL){
		vector<Patch*> branchA = getPatchList(root.childA);
		vector<Patch*> branchB = getPatchList(root.childB);

		for(size_t i = 0; i < branchB.size(); i++){
			branchA.push_back(branchB.at(i));
		}
		return branchA;
	}
	else{
		vector<Patch*> result;
		result.push_back(&root.patchInfo);
		return result;
	}
}

vector<Patch*> PatchTree::getPatchList(PatchTreeNode* curNode){
	if(curNode->childA != NULL && curNode->childB != NULL){
		vector<Patch*> branchA = getPatchList(curNode->childA);
		vector<Patch*> branchB = getPatchList(curNode->childB);

		for(size_t i = 0; i < branchB.size(); i++){
			branchA.push_back(branchB.at(i));
		}
		return branchA;
	}
	else{
		vector<Patch*> result;
		result.push_back(&(curNode->patchInfo));
		return result;
	}
}